#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <pthread.h>
#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "LockGuard.hpp"

using namespace log_ns;

using task_t = std::function<void()>; // 线程池要执行的任务
class Route
{
public:
    Route()
    {
        pthread_mutex_init(&_mtx, nullptr);
    }

    // 检查用户是否是第一次发言
    void CheckOnlineUsers(InetAddr &who)
    {
        LockGuard lockguard(&_mtx);
        for (auto &user : _online_users)
        {
            if (user == who)
            {
                LOG(DEBUG, "user [%s] is existent\n", who.AddrStr().c_str());
                return;
            }
        }
        // 用户第一次发送消息
        LOG(DEBUG, "user [%s] is not existent, push it\n", who.AddrStr().c_str());
        _online_users.push_back(who);
    }

    // 用户下线
    void Offline(InetAddr &who)
    {
        LockGuard lockguard(&_mtx);
        auto ite = _online_users.begin();
        for (; ite != _online_users.end(); ite++)
        {
            if (*ite == who)
            {
                _online_users.erase(ite);
                LOG(DEBUG, "%s is offline\n", who.AddrStr().c_str());
                break;
            }
        }
    }

    void ForwardHelper(int sockfd, std::string message, InetAddr who)
    {
        LockGuard lockguard(&_mtx);
        std::string forward_msg = "[" + who.AddrStr() + "] #";
        forward_msg += message;

        // 遍历用户列表中所有用户，发送数据
        for (auto &user : _online_users)
        {
            struct sockaddr_in peer = user.Addr();
            ::sendto(sockfd, forward_msg.c_str(), forward_msg.size(), 0, (struct sockaddr *)&peer, sizeof(peer));
            LOG(DEBUG, "forward message to %s, message: %s\n", user.AddrStr().c_str(), forward_msg.c_str());
        }
    }

    void Forward(int sockfd, const std::string &message, InetAddr &who)
    {
        // 检查用户是否在列表中
        CheckOnlineUsers(who);

        // 检查是否为下线消息
        if (message == "QUIT" || message == "Q")
        {
            Offline(who);
        }
        // 到这里，列表中一定存在用户，向所有用户转发消息
        // 启动线程池，执行转发任务
        task_t t = std::bind(&Route::ForwardHelper, this, sockfd, message, who);
        ThreadPool<task_t>::GetInstance()->Equeue(t);
    }
    ~Route()
    {
        pthread_mutex_destroy(&_mtx);
    }

private:
    std::vector<InetAddr> _online_users; // 在线用户列表
    pthread_mutex_t _mtx;
};